#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time    : 2021/3/21 19:46
# @Author  : Hbber
# @Version : 0.0.0
# @File    : learn_qt5.py
# @Software: PyCharm
# @Org     : AirCas
# @Describe: 

# @Last Modify Time          @Version        @Description
# --------------------       --------        -----------
# 2021/3/21 19:46            0.0.1           None

#

__author__ = 'Ted'

import json
import socket
from queue import Queue, Empty
import time

import numpy as np
import pyqtgraph as pq
from PyQt5 import QtCore
from PyQt5.Qt import *
from pyqtgraph import PlotWidget
from scipy import signal

data_queue = Queue()


def get_timestamp13():
    return round(time.time() * 1000)


def filter_Remove_signal_distortion(signalIn, thresh=1, searchLen=100*5):
    """  去除由于相位展开而造成的信号畸变

    搜索signal中的相邻两个采样值的差，如果有一个正差大于门限thresh 则表示为发现波形畸变
    标志位置1  后向搜索至searchLen长度  如果发现有负跳变  则表示找到波形畸变结束  结束标志置1
    将开始和结束之间的数值整体减掉跳变值  返回修改后的信号

    :param signalIn:待处理信号
    :param thresh:门限
    :param searchLen:向后搜索的长度
    :return:处理后的信号signal np一维数组
    """
    startIndex = 0
    endIndex = 0
    i = 0
    Flag = 0
    oldValue = signalIn[0]

    signalInLen = len(signalIn)
    while i < signalInLen:
        diff = signalIn[i] - oldValue
        if diff > thresh:
            startIndex = i
            xiuzhengVakue = diff
            searchLenRel = min(searchLen, (signalInLen - i - 1))
            ii = 0
            while ii < searchLenRel:
                diff = signalIn[ii + startIndex] - oldValue
                if diff < -thresh:
                    endIndex = ii + startIndex
                    Flag = 1
                    break
                oldValue = signalIn[ii + startIndex]
                ii = ii + 1
            if Flag:
                jj = 0
                while jj < endIndex - startIndex:
                    signalIn[jj + startIndex] = signalIn[jj + startIndex] - xiuzhengVakue
                    jj = jj + 1
                Flag = 0
                i = endIndex - 1
            else:
                jj = 0
                while jj < signalInLen - startIndex:
                    signalIn[jj + startIndex] = signalIn[jj + startIndex] - xiuzhengVakue
                    jj = jj + 1
        oldValue = signalIn[i]
        i = i + 1

    i = 0
    while i < signalInLen:
        diff = signalIn[i] - oldValue
        if diff < -thresh:
            startIndex = i
            # print('负跳变：%d' % startIndex)
            xiuzhengVakue = abs(diff)
            searchLenRel = min(searchLen, (signalInLen - i - 1))
            ii = 0
            while ii < searchLenRel:
                diff = signalIn[ii + startIndex] - oldValue
                if diff > thresh:
                    endIndex = ii + startIndex
                    Flag = 1
                    break
                oldValue = signalIn[ii + startIndex]
                ii = ii + 1
            if Flag:
                jj = 0
                while jj < endIndex - startIndex:
                    signalIn[jj + startIndex] = signalIn[jj + startIndex] + xiuzhengVakue
                    jj = jj + 1
                Flag = 0
                i = endIndex - 1
            else:
                jj = 0
                while jj < startIndex:
                    signalIn[jj] = signalIn[jj] - xiuzhengVakue
                    jj = jj + 1
        oldValue = signalIn[i]
        i = i + 1

    return signalIn


def remove_zhiliu(bcg, fs):
    # 去除呼吸信号
    f1 = 0.1
    f2 = 25
    w1 = f1 / fs * 2
    w2 = f2 / fs * 2
    b, a = signal.butter(5, w1, 'lowpass')
    bcg_base = signal.filtfilt(b, a, bcg)
    bcg_r_base = bcg - bcg_base
    b, a = signal.butter(5, w2, 'lowpass')
    bcg_end = signal.filtfilt(b, a, bcg_r_base)
    return bcg_end


def filter_discha(signalIn):
    """
    计算连续的相位差
    :param signalIn: 输入的待处理的信号
    :return: 输入信号的连续相位差
    """
    dacha = np.zeros(len(signalIn))
    i = 1
    while i < len(signalIn):
        dacha[i] = signalIn[i] - signalIn[i - 1]
        i = i + 1
    return dacha


def filter_avg(signalIn):
    """
    去除直流分量
    :param signalIn: 输入的待处理的信号
    :return: 去除直流分量之后的信号
    """
    dacha = np.zeros(len(signalIn))
    avg = np.average(signalIn)
    i = 1
    while i < len(signalIn):
        dacha[i] = signalIn[i] - avg
        i = i + 1
    return dacha


def filter_removeInpluseNoise(signalIn, thresh=0.1):
    """
    去除脉冲噪声
    :param signalIn: 输入的待处理信号
    :param thresh: 门限
    :return: 去除脉冲噪声后的信号
    """
    i = 1
    while i < len(signalIn) - 1:
        forwardDiff = signalIn[i] - signalIn[i - 1]
        backwardDiff = signalIn[i] - signalIn[i + 1]
        if ((forwardDiff > thresh) and (backwardDiff > thresh)) or (
                (forwardDiff < -thresh) and (backwardDiff < -thresh)):
            signalIn[i] = signalIn[i - 1] + (0.5 * (signalIn[i + 1] - signalIn[i - 1]))
        else:
            signalIn[i] = signalIn[i]
        i = i + 1
    return signalIn


class SocketClientThread(QtCore.QThread):
    def __init__(self):
        super(SocketClientThread, self).__init__()
        try:
            print('尝试建立连接...')
            self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.s.connect(('10.0.0.222', 6666))
            print(self.s.recv(4096))
        except socket.error as msg:
            print(msg)
            sys.exit(1)

    def run(self):
        print('Socket Thread Run...')
        while True:
            try:
                data = self.s.recv(4096)
            except Exception as e:
                print(e)
                break
            points = json.loads(data)["data_50"]
            print('队列长度：{0}， 数据包长度：{1}'.format(data_queue.qsize(), len(points)))
            for point in points:
                data_queue.put(point)
        print('Socket Thread Exit!')


class Window(QWidget):
    def __init__(self):
        super().__init__()
        # 设置下尺寸
        self.resize(600, 600)
        # 添加 PlotWidget 控件
        self.plotWidget_ted = PlotWidget(self)
        # 设置该控件尺寸和相对位置
        self.plotWidget_ted.setGeometry(QtCore.QRect(0, 0, 600, 600))

        # 仿写 mode1 代码中的数据
        # 生成 300 个正态分布的随机数
        self.data1 = np.zeros(3000)

        self.curve1 = self.plotWidget_ted.plot(self.data1, name="mode1")
        self.plotWidget_ted.setYRange(-100000, 100000)

        # 启动数据接收线程
        self.socket_t = SocketClientThread()
        self.socket_t.start()

        # 设定定时器
        self.timer = pq.QtCore.QTimer()
        # 定时器信号绑定 update_data 函数
        self.timer.timeout.connect(self.update_data)
        # 定时器间隔40ms，可以理解为 40ms 刷新一次数据
        self.timer.start(35)
        self.in_time = get_timestamp13()
        self.sync_num = 0
        self.points_sum = 0
        self.init_array = False

    # 数据左移
    def update_data(self):
        if self.init_array is False:
            point_val = data_queue.get()
            for d in self.data1:
                d = point_val
        start_time = get_timestamp13()
        if self.sync_num > 10 and data_queue.qsize() > 50:
            point_num = data_queue.qsize() - 50
            self.sync_num = 0
        else:
            point_num = 4
        for i in range(point_num):
            self.data1[:-1] = self.data1[1:]  # shift data in the array one sample left
            # (see also: np.roll)
            try:
                self.data1[-1] = data_queue.get_nowait()
            except Empty as e:
                # print('error')
                self.data1[-1] = 0
                pass
        # 增加点计数
        self.points_sum = self.points_sum + point_num
        # 数据填充到绘制曲线中
        if self.points_sum > 3000:
            data_dis_cha = remove_zhiliu(self.data1, fs=100)
            self.curve1.setData(data_dis_cha)
        else:
            self.curve1.setData(self.data1)
        print('绘图耗时：{0}ms, 调用间隔：{1}ms, 点数量：{2}个'.format(
            get_timestamp13() - start_time,
            get_timestamp13() - self.in_time,
            point_num))
        self.in_time = get_timestamp13()
        self.sync_num = self.sync_num + 1


if __name__ == '__main__':
    import sys

    # PyQt5 程序固定写法
    app = QApplication(sys.argv)

    # 将绑定了绘图控件的窗口实例化并展示
    window = Window()
    window.show()

    # PyQt5 程序固定写法
    sys.exit(app.exec())
